import Web3 from "web3";
import BigNumber from "bignumber.js";
import { HandleData, AddPreZero } from "./utils";

/**
 * 所需地址
 */
export const address = {
  // 代币地址 用途：【】
  TOKEN: "0x.....................",
  // 接收地址 用途：【转账接收地址...】
  RECEIVE_ADDRESS: "0x....................."
};

// web3 Start
/**
 * 初始化Web3
 *
 * @returns 返回一个Web3实例
 * @throws 初始化Web3时发生错误，将抛出异常
 */
export const InitWeb3 = async () => {
  try {
    // 尝试使用window.web3提供的provider
    if (typeof window.web3 !== "undefined") {
      return new Web3(window.web3.currentProvider);
    } else {
      // Fallback to HttpProvider if window.web3 is not available
      const HttpProvider = "http://127.0.0.1:8545";
      return new Web3(new Web3.providers.HttpProvider(HttpProvider));
    }
  } catch (error) {
    // 错误处理逻辑
    console.error("Failed to initialize Web3:", error);
    throw error; // 抛出错误以便上层处理
  }
};
// web3 End

/**
 * 请求以太坊账户
 *
 * @returns 返回一个Promise，resolve值为请求到的第一个账户地址
 */
export const EthRequestAccounts = async () => {
  const accounts = await window.ethereum.request({
    method: "eth_requestAccounts",
  });
  return accounts[0];
};

/**
 * 获取以太坊链ID
 *
 * @param polling 是否进行轮询获取链ID
 * @returns 链ID
 */
export const EthChainId = async (polling) => {
  if (polling) {
    return new Promise((resolve) => {
      const pollingInterval = setInterval(() => {
        if (window.ethereum?.chainId) {
          clearInterval(pollingInterval);
          resolve(window.ethereum.chainId);
        }
      }, 100);
    });
  } else {
    const chainId = await window.ethereum.request({
      method: "eth_chainId",
    });
    return chainId;
  }
};

/**
 * 获取以太坊Gas价格
 *
 * @returns 返回以太坊Gas价格
 */
export const GetGasPrice = async () => {
  const web3 = await InitWeb3();
  const gasPrice = await web3.eth.getGasPrice();
  return gasPrice;
};

/**
 * 获取gas限制
 *
 * @param param0 参数对象
 * @param param0.from 当前地址
 * @param param0.to 合约地址
 * @param param0.amount 转账金额
 * @param param0.pow 幂次，默认为10的18次方
 * @param param0.props 其他参数
 * @returns 返回gas限制
 */
export const GetGasLimit = async ({
  from,
  to,
  amount,
  pow = Math.pow(10, 18),
  ...props
}) => {
  const web3 = await InitWeb3();
  const gasPrice = await GetGasPrice();
  const _amount = new BigNumber(amount).times(pow);

  const collection = props.collection
    ? AddPreZero(props.collection.substr(2))
    : "";

  const params = {
    from, // 当前地址
    to, // 合约地址
    gasPrice,
    value: "0x00",
    data: HandleData({
      type: "a9059cbb",
      suffix: `
        ${collection}
        ${AddPreZero(_amount.toString(16))}`,
    }),
  };
  return await web3.eth.estimateGas(params);
};

/**
 * 获取以太坊地址的余额
 *
 * @param address 以太坊地址
 * @param pow 幂次，默认为18，用于将wei转换为ether
 * @returns 返回以太坊地址的余额，单位为ether
 */
export const EthGetBalance = async (address, pow = Math.pow(10, 18)) => {
  const balance =
    (await window.ethereum.request({
      method: "eth_getBalance",
      params: [address, "latest"],
      id: 1,
    })) / pow;
  return await balance;
};

/**
 * 获取以太坊代币余额
 *
 * @param address 代币持有者地址
 * @param tokenAddress 代币合约地址
 * @param pow 幂指数，用于将余额转换为十进制数（默认为18）
 * @returns 返回代币余额（十进制数）
 * @throws 当请求失败时抛出异常
 */
export const EthGetTokenBalance = async ({
  address: from,
  tokenAddress: to,
  pow = Math.pow(10, 18)
}) => {
  try {
    const web3 = await InitWeb3();
    const txHash = await window.ethereum.request({
      jsonrpc: "2.0",
      method: 'eth_call',
      params: [{
        from,
        to,
        data: "0x70a08231000000000000000000000000" + from.slice(2)
      }, "latest"],
      id: 1
    });

    if (txHash === "0x") {
      return 0;
    }

    const balance = web3.utils.hexToNumber(txHash) / pow;
    return balance;
  } catch (error) {
    throw error;
  }
};


/**
 * 根据交易哈希值获取交易信息
 *
 * @param hash 交易哈希值
 * @param polling 是否使用轮询方式查询交易信息，默认为false
 * @returns 返回Promise对象，解析值为交易信息对象，如果查询失败则返回错误信息
 */
export const EthGetTransactionByHash = async (hash, polling = false) => {
  if (!polling) {
    return window.ethereum.request({
      method: "eth_getTransactionByHash",
      params: [hash],
    });
  } else {
    return new Promise((resolve, reject) => {
      const intervalId = setInterval(() => {
        window.ethereum
          .request({
            method: "eth_getTransactionByHash",
            params: [hash],
          })
          .then((res) => {
            if (res && res.transactionIndex !== null) {
              clearInterval(intervalId);
              resolve(res);
            }
          })
          .catch((error) => {
            clearInterval(intervalId);
            reject(error);
          });
      }, 500);
    });
  }
};

/**
 * 发送以太坊交易
 *
 * @param from 交易发起者地址
 * @param to 交易接收者地址
 * @param amount 交易金额，单位为wei
 * @param pow 幂值，默认为10的18次方
 * @param gasLimit 交易gas限制，单位为wei
 * @param gas 交易gas价格，单位为wei
 * @param value 交易的value字段，默认为0x00
 * @param dataSuffix 自定义的data后缀
 * @param type 交易类型，默认为"a9059cbb"
 * @param props 其他参数
 * @returns 返回交易哈希
 */
export const EthSendTransaction = async ({
  from,
  to,
  amount,
  pow = Math.pow(10, 18),
  gasLimit,
  gas,
  value = "0x00",
  dataSuffix,
  type = "a9059cbb",
  ...props
}) => {
  const web3 = await InitWeb3();
  const gasPrice = await GetGasPrice();
  const _amount = new BigNumber(amount).multipliedBy(pow);

  const collection = props.collection
    ? AddPreZero(props.collection.substr(2))
    : "";

  // 格式化字符串以避免不期望的空格
  const suffix = dataSuffix
    ? dataSuffix
    : `${collection}${AddPreZero(_amount.toString(16))}`;

  const params = [
    {
      gasPrice: web3.utils.toHex(gasPrice),
      gasLimit: gasLimit ? web3.utils.toHex(gasLimit) : undefined,
      gas: gas ? web3.utils.toHex(gas) : undefined,
      from,
      to,
      value,
      data: HandleData({
        type,
        suffix,
      }),
    },
  ];

  return await window.ethereum.request({
    method: "eth_sendTransaction",
    params,
  });
};
